namespace DotNetNuke.Data
{
    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    public sealed class SqlCommandGenerator
    {
        public static object[] NoValues;
        public static string ReturnValueParameterName = "RETURN_VALUE";

        private SqlCommandGenerator()
        {
            throw new NotSupportedException();
        }

        public static SqlCommand GenerateCommand(SqlConnection Connection, MethodInfo Method, object[] Values, [Optional, DefaultParameterValue(CommandType.StoredProcedure)] CommandType SQLCommandType, [Optional, DefaultParameterValue("")] string SQLCommandText)
        {            
            if (Method == null)
            {
                Method = (MethodInfo) new StackTrace().GetFrame(1).GetMethod();
            }
            SqlCommand command = new SqlCommand();
            command.Connection = Connection;
            command.CommandType = SQLCommandType;
            if (SQLCommandText.Length == 0)
            {
                command.CommandText = Method.Name;
            }
            else
            {
                command.CommandText = SQLCommandText;
            }
            if (command.CommandType == CommandType.StoredProcedure)
            {
                GenerateCommandParameters(command, Method, Values);
                command.Parameters.Add(ReturnValueParameterName, SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
            }
            return command;
        }

        private static void GenerateCommandParameters(SqlCommand command, MethodInfo method, object[] values)
        {
            ParameterInfo[] methodParameters = method.GetParameters();
            int paramIndex = 0;
            foreach (ParameterInfo paramInfo in methodParameters)
            {
                if (!Attribute.IsDefined(paramInfo, typeof(NonCommandParameterAttribute)))
                {
                    SqlParameterAttribute paramAttribute = (SqlParameterAttribute) Attribute.GetCustomAttribute(paramInfo, typeof(SqlParameterAttribute));
                    if (paramAttribute == null)
                    {
                        paramAttribute = new SqlParameterAttribute(null, SqlDbType.BigInt, 0, 0, 0, (ParameterDirection) 0);
                    }
                    SqlParameter sqlParameter = new SqlParameter();
                    if (paramAttribute.IsNameDefined)
                    {
                        sqlParameter.ParameterName = paramAttribute.Name;
                    }
                    else
                    {
                        sqlParameter.ParameterName = paramInfo.Name;
                    }
                    if (!sqlParameter.ParameterName.StartsWith("@"))
                    {
                        sqlParameter.ParameterName = "@" + sqlParameter.ParameterName;
                    }
                    if (paramAttribute.IsTypeDefined)
                    {
                        sqlParameter.SqlDbType = paramAttribute.SqlDbType;
                    }
                    if (paramAttribute.IsSizeDefined)
                    {
                        sqlParameter.Size = paramAttribute.Size;
                    }
                    if (paramAttribute.IsScaleDefined)
                    {
                        sqlParameter.Scale = paramAttribute.Scale;
                    }
                    if (paramAttribute.IsPrecisionDefined)
                    {
                        sqlParameter.Precision = paramAttribute.Precision;
                    }
                    if (paramAttribute.IsDirectionDefined)
                    {
                        sqlParameter.Direction = paramAttribute.Direction;
                    }
                    else if (paramInfo.ParameterType.IsByRef)
                    {
                        if (paramInfo.IsOut)
                        {
                            sqlParameter.Direction = ParameterDirection.Output;
                        }
                        else
                        {
                            sqlParameter.Direction = ParameterDirection.InputOutput;
                        }
                    }
                    else
                    {
                        sqlParameter.Direction = ParameterDirection.Input;
                    }
                    sqlParameter.Value = RuntimeHelpers.GetObjectValue(values[paramIndex]);
                    command.Parameters.Add(sqlParameter);
                    paramIndex++;
                }
            }
        }
    }
}

